package org.nf.web.exception;

import cn.hutool.core.util.ReflectUtil;
import org.nf.web.annotation.ExceptionAdvice;
import org.nf.web.annotation.ExceptionHandler;
import org.nf.web.config.Configure;
import org.nf.web.servlet.HandlerExceptionResolver;
import org.nf.web.servlet.View;
import org.nf.web.view.DefaultView;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.ServiceLoader;
import java.util.Set;

/**
 * @Author lzp
 * @Date 2024-05-21
 * 基于注解的全局异常解析器
 */
public class AnnotationHandlerExceptionResolver  implements HandlerExceptionResolver {
    /**
     * 存放所有带有@ExceptionAdvice注解的异常处理方法
     */
    private List<Method> handlerExMethods = new ArrayList<>();


    @Override
    public void init(Configure configure) {
        Set<Class<?>> classes = configure.getClasses();
        parseHandlerExMethods(classes);
        //对集合的排序
        sortExMethods();
    }

    /**
     * 扫描带有@ExceptionHandler
     * @param classes 所有的class
     */
    private void parseHandlerExMethods(Set<Class<?>> classes){
        classes.forEach(clazz->{
            if (clazz.isAnnotationPresent(ExceptionAdvice.class)){
                for (Method method : clazz.getMethods()){
                    if (method.isAnnotationPresent(ExceptionHandler.class)){
                        handlerExMethods.add(method);
                    }
                }
            }
        });
    }

    /**
     * 将异常按照从小到大的级别进行排序
     */
    @SuppressWarnings("all")
    private void sortExMethods(){
        handlerExMethods.sort((m1,m2)->
                m1.getAnnotation(ExceptionHandler.class).value()
                        .isAssignableFrom(
                                m2.getAnnotation(ExceptionHandler.class).value()
                        ) ? 1 : -1);
    }

    @Override
    public View resolveException(Throwable t) {
        View view =null;
        for (Method method : handlerExMethods){
            Class<?> exClazz = method.getAnnotation(ExceptionHandler.class).value();
            if (exClazz.isAssignableFrom(t.getClass())){
                //调用异常处理方法
                Object object = invokeHandlerMethod(method, t);
                //解析为视图
                view = resolveView(object);
                break;
            }
        }
        return null;
    }


    /**
     * 调用全局异常处理方法
     *
     * @param method
     * @param t
     * @return
     */
    private Object invokeHandlerMethod(Method method, Throwable t){
        //创建异常处理类的实例
        Object instance = ReflectUtil.newInstance(method.getDeclaringClass());
        //调用异常处理烦方法
        return ReflectUtil.invoke(instance,method,t);
    }

    /**
     * 解析为视图对象
     * @param obj 异常处理方法的返回值
     * @return 视图
     */
    private  View resolveView(Object obj){
        if (obj != null){
            return (obj instanceof View) ? (View)obj
                    : new DefaultView(obj);
        }
        return null;
    }
}
